/**

This file is part of MaCI/GIMnet.

MaCI/GIMnet is free software: you can redistribute it and/or modify it 
under the terms of the GNU Lesser General Public License as published 
by the Free Software Foundation, either version 3 of the License, or 
(at your option) any later version.

MaCI/GIMnet is distributed in the hope that it will be useful, but WITHOUT 
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public 
License for more details.

You should have received a copy of the GNU Lesser General Public 
License along with GIMnet. (See COPYING.LESSER) If not, see 
<http://www.gnu.org/licenses/>.

**/
/**
 * $Id: TaskCtrlTypes.hpp,v 1.23 2010-01-07 08:05:39 mmatusia Exp $
 *
 * \file
 * \brief Dataelement containers for the TaskCtrl interface.
 * \author Antti Maula <antti.maula@tkk.fi>, Marek Matusiak
 *
 */
#ifndef _MACI_TASKCTRLTYPES_HPP_
#define _MACI_TASKCTRLTYPES_HPP_
#include <inttypes.h>
#include "ownutils.h"
#include "owndebug.h"
#include "common/text.hpp"
#include "common/timestamp.hpp"

namespace MaCI {

  /** MaCI - TaskCtrl interface.
   *
   * This namespace contains all the methods and types related
   * to the TaskCtrl interface.
   *
   * TaskCtrl is intended for controlling Task engines in the
   * GIMnet/MaCI system. The TaskCtrl interface includes support for
   * the 'Task' type, handling the higher level mission control, as
   * well as the 'MicroTask' type which is responsible for running the
   * real operations related to a specific task.
   *
   * \note This interface is still under heavy developement. Please
   * consider this interface to be on Alpha stage of testing before
   * this note is removed!
   */
  namespace TaskCtrl {

    /** Enumeration types for TaskCtrl data elements.
     */
    enum ETaskCtrlType {
      KTypeUnknown               = -1, ///< Unknown type.
      KTypeTimestamp             = 1,  ///< Common::TTimestamp element.
      KTypeCommand               = 2,  ///< TCommand element.
      KTypeEvaluation            = 5,  ///< TTaskCtrlEvaluation
      KTypeStatusEvent           = 6,   ///< TTaskCtrlStatusEvent element.
      KTypeStateCommand          = 7,  ///< TTaskStateCommand element.
      KTypeTaskCtrlXML           = 8,  ///< TTaskCtrlXML
      KTypeRegistration          = 9, ///< TTaskCtrlRegistration
      KTypeTaskState             = 10, ///< TTaskCtrlTaskState
      KTypeReward                = 11, ///< TTaskCtrlReward
      KTypeContract              = 12, ///< TTaskCtrlContract
      KTypeErrorString           = 13  ///< TErrorString
    };


    /** Cmd types for the TCommand structure field 'TCommand::cmd'.
     */
    enum ETaskCtrlCommand {

        //New specification (Marek)
        //Settings:
        KCommandAddTask            =   1,

        KCommandRemoveTask         =   2,

        KCommandSetTaskState       =   3,

        //Gettings:
        KCommandGetTaskState       =   4,

        KCommandGetTask            =   5,  
                
        KCommandGetCompetences     = 6,
        KCommandGetTaskLibrary     = KCommandGetCompetences,
       
        
        KCommandEvaluateTask       =   7,
        
        //Other
      /** Status event.
       *
       */
        KCommandStatusEvent        =   9,
     
        KCommandRegister           =   10,
        
        KCommandGetStatus          =   11,
        KCommandReward             =   12,
        KCommandGetTasks           =   13,

        KCommandStartTaskCtrl      =   14,
        KCommandStopTaskCtrl       =   15,
        KCommandPauseTaskCtrl      =   16,
        KCommandAddTaskToLibrary   =   17,
        KCommandRemoveTaskFromLibrary = 18,
        


        
    };


    /** Flag types for TCommand structure field 'TCommand::flags'
     */
    enum ETaskCtrlCommandFlag {
        KCommandFlagDefault = 0,
      /** The message is a reply to previously issued command.
       *
       */

        KCommandFlagReply = 1,
        /**
         * Flag for indicating that a module does not support the given
         * command. 
         */
        
        KCommandFlagNotSupported = 2,
        KCommandFlagReplyCmdError = 3
    };
    
    /** Specifies types for the states of a task.
     *
     */
    enum ETaskCtrlTaskState {
       KTaskStateUnknown = -1,
       KTaskStateInit = 1,
       KTaskStateStart = 2,
       KTaskStateStop = 3,
       KTaskStatePause = 4,
       KTaskStateFinished = 5,
       KTaskStateRunning = 6,
       KTaskStateInterrupted = 7,
       KTaskStateMonitoring = 8, //sold task to someone else, now tracking status
       KTaskStateRemoved = 9,
       KTaskStateError = 10
       
    };
    enum ETaskCtrlState{
      KTaskCtrlStateRunning = 1,    ///< Task controller is running
      KTaskCtrlStateStopped = 2,    ///< Task controller is stopped
      KTaskCtrlStatePaused = 3      ///< Task controller is paused
    };
    
    /** Specifies command enums for changing a task's state.
     *
     */
    enum ETaskCtrlTaskStateCommand {
       KTaskStateCommandUnknown = -1,
       KTaskStateCommandInit = 1,
       KTaskStateCommandStart = 2,
       KTaskStateCommandStop = 3,
       KTaskStateCommandPause = 4,
       KTaskStateCommandContinue = 5,
       KTaskStateCommandAuto = 6    
    };

    /** TTaskID utility struct.
     *  Used embedded in command structures.
     *  Use zero in major or minor number to affect all tasks of that
     *  level.
     */    
    struct TTaskCtrlTaskID {
      TTaskCtrlTaskID(const unsigned int aTypeID0 = 0,
                      const unsigned int aTypeID1 = 0,
                      const unsigned int aTypeID2 = 0,
                      const unsigned int aTypeID3 = 0,
                      const unsigned int aTypeID4 = 0,
                      const unsigned int aTypeID5 = 0,
                      const unsigned int aTypeID6 = 0,
                      const unsigned int aHost = 0,
                      const unsigned int aOwner = 0,
                      const unsigned int aTaskID = 0)

        :    typeID0(aTypeID0),
             typeID1(aTypeID1),
             typeID2(aTypeID2),
             typeID3(aTypeID3),
             typeID4(aTypeID4),
             typeID5(aTypeID5),
             typeID6(aTypeID6),
             host(aHost),
             owner(aOwner),
             taskID(aTaskID){}
      void Print(int lvl) const {
        dPrint(lvl,"TTaskID:: typeID0 = %u typeID1 = %u typeID2 = %u typeID3 = %u typeID4 = %u typeID5 = %u typeID6 = %u host = %u owner = %u taskID = %u ",
               typeID0,
               typeID1,
               typeID2,
               typeID3,
               typeID4,
               typeID5,
               typeID6,
               host,
               owner,
               taskID);
      }

      std::string GetString() const{
          std::stringstream out;

          out << "TTaskCtrlTaskID: typeID0 :"<<typeID0<<" typeID1 :"<<typeID1<<" typeID2 :"<<typeID2<<" typeID3 :"<<typeID3<<" typeID4 "<<typeID4<<" typeID5 "<<typeID5<<" typeID6 "<<typeID6<<" host "<<host<<" owner "<<owner<<" taskID "<<taskID;
          
          return out.str();
      }

      uint32_t typeID0;        ///< ID which refers to the 0 hierarchy level
      uint32_t typeID1;        ///< ID which refers to the 1 hierarchy level
      uint32_t typeID2;        ///< ID which refers to the 2 hierarchy level
      uint32_t typeID3;        ///< ID which refers to the 3 hierarchy level
      uint32_t typeID4;        ///< ID which refers to the 4 hierarchy level
      uint32_t typeID5;        ///< ID which refers to the 5 hierarchy level
      uint32_t typeID6;        ///< ID which refers to the 6 hierarchy level

      uint32_t host;           ///< ID of the TaskCtrl server executing the task
      uint32_t owner;          ///< ID of the client that added the task
      uint32_t taskID;         ///< Unique identifying number for each added task in the table. Chosen by the server
                               /// after adding


     
    };
    /** TTaskCtrlClassCompare utility struct.
     *  Used for comparing TTaskCtrlTaskIDs, in std::maps or such.
     */    
    struct TTaskCtrlClassCompare {
        bool operator() (const TTaskCtrlTaskID& lhs, const TTaskCtrlTaskID& rhs) const { 
            
          if(lhs.taskID != rhs.taskID) {
            return lhs.taskID<rhs.taskID;
          }            
          if(lhs.owner != rhs.owner) {
            return lhs.owner<rhs.owner;
          }
          if (lhs.host != rhs.host) {
            return lhs.host<rhs.host;
          }

          if (lhs.typeID0 != rhs.typeID0) {
            return lhs.typeID0<rhs.typeID0;
          }
          if (lhs.typeID1 != rhs.typeID1) {
            return lhs.typeID1<rhs.typeID1;
          }
          if (lhs.typeID2 != rhs.typeID2) {
            return lhs.typeID2<rhs.typeID2;
          }
          if (lhs.typeID3 != rhs.typeID3) {
            return lhs.typeID3<rhs.typeID3;
          }
          if (lhs.typeID4 != rhs.typeID4) {
            return lhs.typeID4<rhs.typeID4;
          }
          if (lhs.typeID5 != rhs.typeID5) {
            return lhs.typeID5<rhs.typeID5;
          }
          else {
            return lhs.typeID6<rhs.typeID6;                                                    
          }
        }
    };

    struct TTaskCtrlClassCompareTypeIDs {
        bool operator() (const TTaskCtrlTaskID& lhs, const TTaskCtrlTaskID& rhs) const { 
            
          if (lhs.typeID0 != rhs.typeID0) {
            return lhs.typeID0<rhs.typeID0;
          }
          if (lhs.typeID1 != rhs.typeID1) {
            return lhs.typeID1<rhs.typeID1;
          }
          if (lhs.typeID2 != rhs.typeID2) {
            return lhs.typeID2<rhs.typeID2;
          }
          if (lhs.typeID3 != rhs.typeID3) {
            return lhs.typeID3<rhs.typeID3;
          }
          if (lhs.typeID4 != rhs.typeID4) {
            return lhs.typeID4<rhs.typeID4;
          }
          if (lhs.typeID5 != rhs.typeID5) {
            return lhs.typeID5<rhs.typeID5;
          }
          else {
            return lhs.typeID6<rhs.typeID6;                                                    
          }
        }
    };
    
    /** TaskCtrl command.
     *  Header sent for sent commands
     *
     * \see ETaskCtrlCommand
     */
    struct TCommand {
      TCommand(const unsigned int aCmd = 0,
               const ETaskCtrlCommandFlag aFlags = KCommandFlagDefault,
               const TTaskCtrlTaskID aTaskID = NULL,
               const unsigned int aCommandID = 0)
    :   cmd(aCmd),
          flags(aFlags),
          taskID(aTaskID),
          commandID(aCommandID) {}
      void Print(int lvl) const {
        dPrint(lvl,"TCommand:: cmd = %d, flags = %u, TTaskID:: typeID0 = %u typeID1 = %u typeID2 = %u typeID3 = %u typeID4 = %u typeID5 = %u typeID6 = %u host = %u owner = %u taskID = %u, commandID: %u",
               cmd, 
               flags, 
               taskID.typeID0,
               taskID.typeID1,
               taskID.typeID2,
               taskID.typeID3,
               taskID.typeID4,
               taskID.typeID5,
               taskID.typeID6,
               taskID.host,
               taskID.owner,
               taskID.taskID,
               commandID);
      }

      uint32_t cmd;             ///< Command see ETaskCtrlCommand
      ETaskCtrlCommandFlag flags;           ///< Flags.
      TTaskCtrlTaskID taskID;   ///< ID of task to be affected by this command.
      uint32_t commandID;
    };
    

    /**
     * Struct which defines the state of the task controller
     * \see ETaskCtrlState
     */   
    struct TTaskCtrlState{
      TTaskCtrlState(const ETaskCtrlState aState = KTaskCtrlStateStopped)
        :state(aState){}

      ETaskCtrlState state;
    };

    /** Container used in conjunction with TCommand to change a Task's
     * state.
     * 
     */
    struct TTaskCtrlStateCommand {
      TTaskCtrlStateCommand(const ETaskCtrlTaskStateCommand aCmd = KTaskStateCommandUnknown)
    : cmd(aCmd){}
      void Print(int lvl) const {
        dPrint(lvl,"TTaskStateCommand:: cmd = %d",
               cmd);
      }
      ETaskCtrlTaskStateCommand cmd;             ///< Command see ETaskCtrlCommand
    };
    

    /** TaskCtrlStatus event.
     *
     * This structure contains information about the happened
     * event. It is usually accompanied by an appropriate XML
     * container to specify metadata for the source of the event.
     */
    struct TTaskCtrlTaskState {
      TTaskCtrlTaskState(const TTaskCtrlTaskID aTaskID = NULL,
                         const ETaskCtrlTaskState aTaskState = KTaskStateUnknown,
                         const unsigned int aETC_ms = 0,
                         const float aPercentComplete = 0.0)
      : taskID(aTaskID),
        taskState(aTaskState),
        ETC_ms(aETC_ms),
        percentComplete(aPercentComplete)
      {}
      void Print(int lvl) const {
        dPrint(lvl,"TTaskCtrlTaskState:: TTaskID:: typeID0 = %u typeID1 = %u typeID2 = %u typeID3 = %u typeID4 = %u typeID5 = %u typeID6 = %u host = %u owner = %u taskID = %u, taskState = %d, ETC_ms = %u, percentComplete = %.2f",
               taskID.typeID0,
               taskID.typeID1,
               taskID.typeID2,
               taskID.typeID3,
               taskID.typeID4,
               taskID.typeID5,
               taskID.typeID6,
               taskID.host,
               taskID.owner,
               taskID.taskID,
               taskState, ETC_ms, percentComplete);
      }
      TTaskCtrlTaskID taskID;              
      ETaskCtrlTaskState taskState; ///< State of task
      uint32_t ETC_ms;              ///< Estimated time to complete in ms
      float percentComplete;
    };


    
    typedef TTaskCtrlTaskState TTaskCtrlStatusEvent;
    
    /** TTaskCtrlEvaluation container.
    *
    * Reply to an evaluation request. Header should be TReply.
    * Can be accompanied by an appropriate XML
    * container to specify more evaluation metrics.
    * 
    */    
    struct TTaskCtrlEvaluation {
      TTaskCtrlEvaluation(const TTaskCtrlTaskID aTaskID = NULL,
                            const unsigned int aValidity = 0,
                            const float aValue = 0.0, 
                            const unsigned int aETC_ms = 0
                            )
      : taskID(aTaskID),
        validity(aValidity),
        value(aValue),
        ETC_ms(aETC_ms)
      {}
      void Print(int lvl) const {
        dPrint(lvl,"TTaskCtrlEvaluation:: TTaskID:: typeID0 = %u typeID1 = %u typeID2 = %u typeID3 = %u typeID4 = %u typeID5 = %u typeID6 = %u host = %u owner = %u taskID = %u, validity = %u, value = %.2f, ETC_ms = %u",
                taskID.typeID0,
               taskID.typeID1,
               taskID.typeID2,
               taskID.typeID3,
               taskID.typeID4,
               taskID.typeID5,
               taskID.typeID6,
               taskID.host,
               taskID.owner,
               taskID.taskID,
               validity, value, ETC_ms);
      }
      TTaskCtrlTaskID taskID;   
      uint32_t validity; //can also be acceptance          
      float value;
      uint32_t ETC_ms;              ///< Estimated time to complete in ms
    };
    /** TTaskCtrlReward container.
    *
    * Executor is rewarded with this struct.
    * This can conclude the execution of the task.
    * 
    */    
    struct TTaskCtrlReward {
      TTaskCtrlReward(const TTaskCtrlTaskID aTaskID = NULL,
                            const float aReward = 0.0
                            )
      : taskID(aTaskID),
        reward(aReward)
      {}
      void Print(int lvl) const {
        dPrint(lvl,"TTaskCtrlReward:: TTaskID:: typeID0 = %u typeID1 = %u typeID2 = %u typeID3 = %u typeID4 = %u typeID5 = %u typeID6 = %u host = %u owner = %u taskID = %u, reward = %.2f",
               taskID.typeID0,
               taskID.typeID1,
               taskID.typeID2,
               taskID.typeID3,
               taskID.typeID4,
               taskID.typeID5,
               taskID.typeID6,
               taskID.host,
               taskID.owner,
               taskID.taskID,
               reward);
      }
      TTaskCtrlTaskID taskID;           
      float reward;
    };
    
    /** TTaskCtrlContract container.
    *
    * Details of execution end time, promised reward if any and TaskID
    * 
    */  
    struct TTaskCtrlContract {
      TTaskCtrlContract(const TTaskCtrlTaskID aTaskID = NULL,
                            const float aReward = 0.0, 
                            const uint32_t aDeadline_s = 0,
                            const uint32_t aDeadline_us = 0
                            )
      : taskID(aTaskID),
        reward(aReward),
        deadline_s(aDeadline_s),
        deadline_us(aDeadline_us)
      {}
      void Print(int lvl) const {
        dPrint(lvl,"TTaskCtrlContract:: TTaskID:: typeID0 = %u typeID1 = %u typeID2 = %u typeID3 = %u typeID4 = %u typeID5 = %u typeID6 = %u host = %u owner = %u taskID = %u, reward = %.2f, DL_s: %u, DL_us: %u",
                taskID.typeID0,
               taskID.typeID1,
               taskID.typeID2,
               taskID.typeID3,
               taskID.typeID4,
               taskID.typeID5,
               taskID.typeID6,
               taskID.host,
               taskID.owner,
               taskID.taskID,
               reward, deadline_s, deadline_us);
      }
      TTaskCtrlTaskID taskID;           
      float reward;
      uint32_t deadline_s;
      uint32_t deadline_us; 
    };

    /** TTaskCtrlXML - Task control XML element.
     *
     * XML container, implemented with common dynamic text container.
     */
    typedef Common::TText TTaskCtrlXML;

    typedef Common::TText TErrorString;
  }
}

#endif
